/*
 * Copyright 2020 tu.cn All right reserved. This software is the
 * confidential and proprietary information of tu.cn ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with Tu.cn
 */
package com.onedec.message.websocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.onedec.message.entity.OnedecMsg;
import com.onedec.message.entity.OnedecMsgGroup;
import com.onedec.message.service.MessageService;
import com.onedec.message.service.MsgGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 31014
 * @date 2020/7/13 19:50
 */
@Component
@ServerEndpoint("/chat/{id}")
public class OnMessageWebSocket {
    //以用户id存储会话
    public static Map<Integer, OnMessageWebSocket> sessions = new ConcurrentHashMap<>();
    //以群id存储会话
    public static Map<Integer, Map<Integer, OnMessageWebSocket>> group = new ConcurrentHashMap<>();
    private static ObjectMapper objectMapper;
    private Integer eId;
    private Session session;
    @Autowired
    private static MsgGroupService msgGroupService;

    @Autowired
    public void setMsgGroupService(MsgGroupService msgGroupService) {
        OnMessageWebSocket.msgGroupService = msgGroupService;
    }

    @Autowired
    private static MessageService messageService;

    @Autowired
    public void setMessageService(MessageService messageService) {
        OnMessageWebSocket.messageService = messageService;
    }

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        OnMessageWebSocket.objectMapper = objectMapper;
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("id") Integer id) {
        eId = id;
        this.session = session;
        sessions.put(id, this);
        final List<OnedecMsgGroup> groups = msgGroupService.selectGroupByEmp(id);
        groups.forEach(e -> {
            Map<Integer, OnMessageWebSocket> groupSession = group.get(e.getMsgGroupId());
            if (groupSession == null) {
                groupSession = new ConcurrentHashMap<>();
                groupSession.put(id, this);
                group.put(e.getMsgGroupId(), groupSession);
                groupSession.put(id, this);
            }
            if (groupSession != null) {
                groupSession.put(id, this);
            }
        });

    }

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        final Map on = objectMapper.readValue(message, Map.class);
        System.out.println(on);
        if ("friend".equals(((HashMap) (((HashMap) on.get("data")).get("to"))).get("type"))) {
            sendMessage(on, session);
        }
        if ("group".equals(((HashMap) (((HashMap) on.get("data")).get("to"))).get("type"))) {
            sendGroup(on, session);
        }
    }


    @OnClose
    public void onclose() {
        System.out.println("--");
    }

    @OnError
    public void onError(Throwable e) {
        e.printStackTrace();
    }

    public void sendMessage(Map<String, Object> message, Session session) throws IOException {
        final Map mine = (HashMap) ((HashMap) message.get("data")).get("mine");
        final Map to = (HashMap) ((HashMap) message.get("data")).get("to");
        final Object id = to.get("id");
        final OnMessageWebSocket on = sessions.get((int) to.get("id"));
        if (on == null || !on.session.isOpen()) {
            final OnedecMsg onedecMsg = new OnedecMsg();
            onedecMsg.setMsgContent((String) mine.get("content"));
            onedecMsg.setMsgSenderId(this.eId);
            onedecMsg.setMsgReceiverId((int) to.get("id"));
            onedecMsg.setMsgStatus(2);
            messageService.insertMessage(onedecMsg);
            return;
        }
        final HashMap<String, Object> onMessage = new HashMap<>();
        onMessage.put("username", mine.get("username"));
        onMessage.put("avatar", mine.get("avatar"));
        onMessage.put("id", mine.get("id"));
        onMessage.put("type", to.get("type"));
        onMessage.put("content", mine.get("content"));
        onMessage.put("mine", false);
        onMessage.put("fromid", mine.get("id"));
        onMessage.put("timestamp", new Date().getTime());
        final String s = objectMapper.writeValueAsString(onMessage);
        on.session.getBasicRemote().sendText(s);
    }

    private void sendGroup(Map message, Session session) throws JsonProcessingException {

        final Map mine = (HashMap) ((HashMap) message.get("data")).get("mine");
        final Map to = (HashMap) ((HashMap) message.get("data")).get("to");
        final Object toId = (Integer) to.get("id");
        final Map<Integer, Map<Integer, OnMessageWebSocket>> map = OnMessageWebSocket.group;
        final Map<Integer, OnMessageWebSocket> toWebsockets = map.get(toId);
        if (toWebsockets == null) {
            return;
        }
        final HashMap<String, Object> onMessage = new HashMap<>();
        onMessage.put("username", mine.get("username"));
        onMessage.put("avatar", mine.get("avatar"));
        onMessage.put("id", to.get("id"));
        onMessage.put("type", to.get("type"));
        onMessage.put("content", mine.get("content"));
        onMessage.put("mine", false);
        onMessage.put("fromid", mine.get("id"));
        onMessage.put("timestamp", new Date().getTime());
        final String s = objectMapper.writeValueAsString(onMessage);
        toWebsockets.forEach((e, a) -> {
            try {
                if (a.eId != eId) {
                    a.session.getBasicRemote().sendText(s);
                }
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        });
    }
}